Initial revision
authorJim Blandy <jimb@redhat.com>
Sun, 14 Mar 1993 22:49:14 +0000 (22:49 +0000)
committerJim Blandy <jimb@redhat.com>
Sun, 14 Mar 1993 22:49:14 +0000 (22:49 +0000)
src/vmstime.c [new file with mode: 0644]
src/vmstime.h [new file with mode: 0644]

diff --git a/src/vmstime.c b/src/vmstime.c
new file mode 100644 (file)
index 0000000..907ec35
--- /dev/null
@@ -0,0 +1,357 @@
+#include "config.h"
+#include "vmstime.h"
+
+long timezone=0;
+int daylight=0;
+
+static char tzname_default[20]="";
+static char tzname_dst[20]="";
+
+char *tzname[2] = { tzname_default, tzname_dst };
+
+static long internal_daylight=0;
+static char daylight_set=0;
+
+static long read_time(const char *nptr, const char **endptr,
+                     int sign_allowed_p)
+{
+  int t;
+
+  *endptr = nptr;
+
+  /* This routine trusts the user very much, and does no checks!
+      The only exception is this: */
+  if (!sign_allowed_p && (*nptr == '-' || *nptr == '+'))
+    return 0;
+
+  t = strtol(*endptr, endptr, 10) * 3600;
+  if (**endptr != ':' || **endptr == '+' || **endptr == '-')
+    return t;
+  (*endptr)++;
+
+  t = t + strtol(*endptr, endptr, 10) * 60;
+  if (**endptr != ':' || **endptr == '+' || **endptr == '-')
+    return t;
+  (*endptr)++;
+
+  return t + strtol(*endptr, endptr, 10);
+}
+
+static void read_dst_time(const char *nptr, const char **endptr,
+                         int *m, int *n, int *d,
+                         int *leap_p)
+{
+  time_t bintim = time(0);
+  struct tm *lc = localtime(&bintim);
+
+  *leap_p = 1;
+  *m = 0;                      /* When m and n are 0, a Julian */
+  *n = 0;                      /* date has been inserted in d */
+
+  switch(*nptr)
+    {
+    case 'M':
+      {
+       /* This routine counts on the user to have specified "Mm.n.d",
+          where 1 <= n <= 5, 1 <= m <= 12, 0 <= d <= 6 */
+
+       *m = strtol(++nptr, endptr, 10);
+       (*endptr)++;            /* Skip the dot */
+       *n = strtol(*endptr, endptr, 10);
+       (*endptr)++;            /* Skip the dot */
+       *d = strtol(*endptr, endptr, 10);
+
+       return;
+      }
+    case 'J':
+      *leap_p = 0;             /* Never count with leap years */
+    default: /* trust the user to have inserted a number! */
+      *d = strtol(++nptr, endptr, 10);
+      return;
+    }
+}
+
+struct vms_vectim
+{
+  short year, month, day, hour, minute, second, centi_second;
+};
+static void find_dst_time(int m, int n, long d,
+                         int hour, int minute, int second,
+                         int leap_p,
+                         long vms_internal_time[2])
+{
+  long status = SYS$GETTIM(vms_internal_time);
+  struct vms_vectim vms_vectime;
+  status = SYS$NUMTIM(&vms_vectime, vms_internal_time);
+
+  if (m == 0 && n == 0)
+    {
+      long tmp_vms_internal_time[2][2];
+      long day_of_year;
+      long tmp_operation = LIB$K_DAY_OF_YEAR;
+
+      status = LIB$CVT_FROM_INTERNAL_TIME(&tmp_operation, &day_of_year,
+                                         vms_internal_time);
+      
+      vms_vectime.month = 2;
+      vms_vectime.day = 29;
+      status = LIB$CVT_VECTIM(&vms_vectime, tmp_vms_internal_time[0]);
+      if (status & 1) /* This is a leap year */
+       {
+         if (!leap_p && d > 59)
+           d ++;               /* If we don't count with 29th Feb,
+                                  and this is a leap year, count up,
+                                  to make day 60 really become the
+                                  1st March. */
+       }
+      /* 1st January, at midnight */
+      vms_vectime.month = 1;
+      vms_vectime.day = 1;
+      vms_vectime.hour = hour;
+      vms_vectime.minute = minute;
+      vms_vectime.second = second;
+      vms_vectime.centi_second = 0;
+      status = LIB$CVT_VECTIM(&vms_vectime, tmp_vms_internal_time[0]);
+      tmp_operation = LIB$K_DELTA_DAYS;
+      status = LIB$CVT_TO_INTERNAL_TIME(&tmp_operation, &d,
+                                       tmp_vms_internal_time[1]);
+      /* now, tmp_vms_interval_time[0] contains 1st Jan, 00:00:00,
+        and  tmp_vms_interval_time[1] contains delta time +d days.
+        Let's just add them together */
+      status = LIB$ADD_TIMES(tmp_vms_internal_time[0],
+                            tmp_vms_internal_time[1],
+                            vms_internal_time);
+    }
+  else
+    {
+      long tmp_vms_internal_time[2];
+      long day_of_week;
+      long tmp_operation = LIB$K_DAY_OF_YEAR;
+
+      if (d == 0) /* 0 is Sunday, which isn't compatible with VMS,
+                    where day_of_week is 1 -- 7, and 1 is Monday */
+       {
+         d = 7; /* So a simple conversion is required */
+       }
+      vms_vectime.month = m;
+      vms_vectime.day = 1;
+      vms_vectime.hour = hour;
+      vms_vectime.minute = minute;
+      vms_vectime.second = second;
+      vms_vectime.centi_second = 0;
+      status = LIB$CVT_VECTIM(&vms_vectime, tmp_vms_internal_time);
+      tmp_operation = LIB$K_DAY_OF_WEEK;
+      status = LIB$CVT_FROM_INTERNAL_TIME(&tmp_operation, &day_of_week,
+                                         tmp_vms_internal_time);
+      d -= day_of_week;
+      if (d < 0)
+       {
+         d += 7;
+       }
+      vms_vectime.day += (n-1)*7 + d;
+      status = LIB$CVT_VECTIM(&vms_vectime, vms_internal_time);
+      if (!(status & 1))
+       {
+         vms_vectime.day -= 7; /* n was probably 5 */
+         status = LIB$CVT_VECTIM(&vms_vectime, vms_internal_time);
+       }
+    }
+}
+
+static cmp_vms_internal_times(long vms_internal_time1[2],
+                             long vms_internal_time2[2])
+{
+  if (vms_internal_time1[1] < vms_internal_time2[1])
+    return -1;
+  else
+    if (vms_internal_time1[1] > vms_internal_time2[1])
+      return 1;
+
+  if (vms_internal_time1[0] < vms_internal_time2[0])
+    return -1;
+  else
+    if (vms_internal_time1[0] > vms_internal_time2[0])
+      return 1;
+
+  return 0;
+}
+
+/* -------------------------- Global routines ------------------------------ */
+
+#ifdef tzset
+#undef tzset
+#endif
+void sys_tzset()
+{
+  char *TZ;
+  char *p, *q;
+
+  if (daylight_set)
+    return;
+
+  daylight = 0;
+
+  if ((TZ = getenv("TZ")) == 0)
+    return;
+
+  p = TZ;
+  q = tzname[0];
+
+  while(*p != '\0'
+       && (*p <'0' || *p > '9') && *p != '-' && *p != '+' && *p != ',')
+    *q++ = *p++;
+  *q = '\0';
+
+  /* This is special for VMS, so I don't care if it doesn't exist anywhere
+     else */
+
+  timezone = read_time(p, &p, 1);
+
+  q = tzname[1];
+
+  while(*p != '\0'
+       && (*p <'0' || *p > '9') && *p != '-' && *p != '+' && *p != ',')
+    *q++ = *p++;
+  *q = '\0';
+
+  if (*p != '-' && *p != '+' && !(*p >='0' && *p <= '9'))
+    internal_daylight = timezone - 3600;
+  else
+    internal_daylight = read_time(p, &p, 1);
+
+  if (*p == ',')
+    {
+      int start_m;
+      int start_n;
+      int start_d;
+      int start_leap_p;
+      int start_hour=2, start_minute=0, start_second=0;
+
+      p++;
+      read_dst_time(p, &p, &start_m, &start_n, &start_d, &start_leap_p);
+      if (*p == '/')
+       {
+         long tmp = read_time (++p, &p, 0);
+         start_hour = tmp / 3600;
+         start_minute = (tmp % 3600) / 60;
+         start_second = tmp % 60;
+       }
+      if (*p == ',')
+       {
+         int end_m;
+         int end_n;
+         int end_d;
+         int end_leap_p;
+         int end_hour=2, end_minute=0, end_second=0;
+
+         p++;
+         read_dst_time(p, &p, &end_m, &end_n, &end_d, &end_leap_p);
+         if (*p == '/')
+           {
+             long tmp = read_time (++p, &p, 0);
+             end_hour = tmp / 3600;
+             end_minute = (tmp % 3600) / 60;
+             end_second = tmp % 60;
+           }
+         {
+           long vms_internal_time[3][2];
+           find_dst_time(start_m, start_n, start_d,
+                         start_hour, start_minute, start_second,
+                         start_leap_p,
+                         vms_internal_time[0]);
+           SYS$GETTIM(&vms_internal_time[1]);
+           find_dst_time(end_m, end_n, end_d,
+                         end_hour, end_minute, end_second,
+                         end_leap_p,
+                         vms_internal_time[2]);
+           if (cmp_vms_internal_times(vms_internal_time[0],
+                                     vms_internal_time[1]) < 0
+               && cmp_vms_internal_times(vms_internal_time[1],
+                                        vms_internal_time[2]) < 0)
+             daylight = 1;
+         }
+       }
+    }
+}  
+
+#ifdef localtime
+#undef localtime
+#endif
+struct tm *sys_localtime(time_t *clock)
+{
+  struct tm *tmp = localtime(clock);
+
+  sys_tzset();
+  tmp->tm_isdst = daylight;
+
+  return tmp;
+}
+
+#ifdef gmtime
+#undef gmtime
+#endif
+struct tm *sys_gmtime(time_t *clock)
+{
+  static struct tm gmt;
+  struct vms_vectim tmp_vectime;
+  long vms_internal_time[3][2];
+  long tmp_operation = LIB$K_DELTA_SECONDS;
+  long status;
+  long tmp_offset;
+  char tmp_o_sign;
+
+  sys_tzset();
+  
+  if (daylight)
+    tmp_offset = internal_daylight;
+  else
+    tmp_offset = timezone;
+
+  if (tmp_offset < 0)
+    {
+      tmp_o_sign = -1;
+      tmp_offset = -tmp_offset;
+    }
+  else
+    tmp_o_sign = 1;
+
+  status = LIB$CVT_TO_INTERNAL_TIME(&tmp_operation, &tmp_offset,
+                                   vms_internal_time[1]);
+  status = SYS$GETTIM(vms_internal_time[0]);
+  if (tmp_o_sign < 0)
+    {
+      status = LIB$SUB_TIMES(vms_internal_time[0],
+                            vms_internal_time[1],
+                            vms_internal_time[2]);
+    }
+  else
+    {
+      status = LIB$ADD_TIMES(vms_internal_time[0],
+                            vms_internal_time[1],
+                            vms_internal_time[2]);
+    }
+
+  status = SYS$NUMTIM(&tmp_vectime, vms_internal_time[2]);
+  gmt.tm_sec = tmp_vectime.second;
+  gmt.tm_min = tmp_vectime.minute;
+  gmt.tm_hour = tmp_vectime.hour;
+  gmt.tm_mday = tmp_vectime.day;
+  gmt.tm_mon = tmp_vectime.month - 1;
+  gmt.tm_year = tmp_vectime.year % 100;
+
+  tmp_operation = LIB$K_DAY_OF_WEEK;
+  status = LIB$CVT_FROM_INTERNAL_TIME(&tmp_operation,
+                                     &gmt.tm_wday,
+                                     vms_internal_time[2]);
+  if (gmt.tm_wday == 7) gmt.tm_wday = 0;
+
+  tmp_operation = LIB$K_DAY_OF_YEAR;
+  status = LIB$CVT_FROM_INTERNAL_TIME(&tmp_operation,
+                                     &gmt.tm_yday,
+                                     vms_internal_time[2]);
+  gmt.tm_yday--;
+  gmt.tm_isdst = daylight;
+
+  return &gmt;
+}
+
diff --git a/src/vmstime.h b/src/vmstime.h
new file mode 100644 (file)
index 0000000..70d23e9
--- /dev/null
@@ -0,0 +1,15 @@
+#ifndef vmstime_h
+#define vmstime_h
+
+#include <time.h>
+#include <libdtdef.h>
+
+extern long timezone;
+extern int daylight;
+extern char *tzname[2];
+
+void sys_tzset();
+struct tm *sys_localtime(time_t *clock);
+struct tm *sys_gmtime(time_t *clock);
+
+#endif /* vmstime_h */